using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Shape;
using GameCamera;
using Light;

namespace CGEx3
{

  public class Game1 : Microsoft.Xna.Framework.Game
  {
    GraphicsDeviceManager graphics;
    Camera mainCamera;
    Vector3[] lights;
    List<IShape> shapes;
    KeyboardState oldState;
    LightPoint light;
    Texture2D metalTexture;
    SpriteBatch spriteBatch;
    RenderTarget2D shadowRenderTarget;

    public Game1()
    {
      graphics = new GraphicsDeviceManager(this);
      graphics.PreferredBackBufferWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
      graphics.PreferredBackBufferHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
      graphics.IsFullScreen = true;
      Content.RootDirectory = "Content";
    }

    protected override void Initialize()
    {
      oldState = Keyboard.GetState();
      Content.RootDirectory = "Content";
      mainCamera = new Camera(true, new Vector3(0.0f, 0.0f, 50.0f), GraphicsDevice.Viewport);
      lights = new Vector3[3];
      shapes = new List<IShape>();
      base.Initialize();
    }

    protected override void LoadContent()
    {
      spriteBatch = new SpriteBatch(GraphicsDevice);
      Effect lightingEffect = Content.Load<Effect>("Lighting");
      light = new LightPoint(mainCamera, lightingEffect, Color.White.ToVector4(), 0.5f, 
        new Vector3(0.0f, 20.0f, 80.0f), Color.White.ToVector4(),new Vector3(0.0f,0.0f,-20.0f));
      metalTexture = Content.Load<Texture2D>("metal");
      shadowRenderTarget = new RenderTarget2D(GraphicsDevice, 2048, 2048, false, SurfaceFormat.HalfSingle, DepthFormat.Depth24);
      IShape sphere1 = new Sphere(new Vector3(-20.0f, -2.0f, 0.0f), 3.0f, graphics.GraphicsDevice, lightingEffect, metalTexture);
      IShape sphere2 = new Sphere(new Vector3(10.0f, -2.0f, -15.0f), 3.0f, graphics.GraphicsDevice, lightingEffect, metalTexture);
      IShape sphere3 = new Sphere(new Vector3(20.0f, -2.0f, 15.0f), 3.0f, graphics.GraphicsDevice, lightingEffect, metalTexture);
      IShape cube1 = new Cube(new Vector3(0.0f, -2.0f, 0.0f), 3.0f, graphics.GraphicsDevice, lightingEffect, metalTexture);
      IShape cube2 = new Cube(new Vector3(0.0f, -2.0f, 10.0f), 3.0f, graphics.GraphicsDevice, lightingEffect, metalTexture);
      IShape cube3 = new Cube(new Vector3(-10.0f, -2.0f, -5.0f), 3.0f, graphics.GraphicsDevice, lightingEffect, metalTexture);
      IShape plane = new Shape.Plane(new Vector3(0.0f, -5.0f, 0.0f), 50.0f, graphics.GraphicsDevice, lightingEffect, metalTexture);
      shapes.Add(sphere1);
      shapes.Add(sphere2);
      shapes.Add(sphere3);
      shapes.Add(cube1);
      shapes.Add(cube2);
      shapes.Add(cube3);
      shapes.Add(plane);
      foreach (var shape in shapes)
        shape.Effect.CurrentTechnique = light.LightingEffect.Techniques["ShadowedSceneTechnique"];
    }

    private void InputDetection()
    {
      KeyboardState keyboardState = Keyboard.GetState();
      if (keyboardState.IsKeyDown(Keys.Escape))
        this.Exit();
      if (keyboardState.IsKeyDown(Keys.L) && !oldState.IsKeyDown(Keys.L))
      {
        light.Rotate = !light.Rotate;
      }
      oldState = keyboardState;
    }

    protected override void Update(GameTime gameTime)
    {
      InputDetection();
      mainCamera.Update();
      light.Update();
      base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
      GraphicsDevice.Clear(Color.Black);
      drawAll(mainCamera);
      base.Draw(gameTime);
    }

    private void drawShadowMap()
    {
      spriteBatch.Begin(0, BlendState.Opaque, SamplerState.PointClamp, null, null);
      spriteBatch.Draw(shadowRenderTarget, new Rectangle(0, 0, 512, 512), Color.White);
      spriteBatch.End();

      GraphicsDevice.Textures[0] = null;
      GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
    }

    private void drawAll(Camera camera)
    {
      GraphicsDevice.SetRenderTarget(shadowRenderTarget);
      GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);
      foreach (var shape in shapes)
      {
        shape.Effect.CurrentTechnique = light.LightingEffect.Techniques["ShadowMapTechnique"];
        shape.drawShape(camera);
      }
      GraphicsDevice.SetRenderTarget(null);
      //drawShadowMap();
      light.LightingEffect.Parameters["ShadowMap"].SetValue((Texture2D)shadowRenderTarget);
      GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);
      foreach (var shape in shapes)
      {
        shape.Effect.CurrentTechnique = light.LightingEffect.Techniques["ShadowedSceneTechnique"];
        shape.drawShape(camera);
      }
    }
  }
}
